/*
 * NormalFitness.java
 *
 * Created on den 30 mars 2007, 23:30
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */
package grex.fitnessfunctions.Classification;

import grex.GP;
import grex.Options;
import grex.Prediction;
import grex.PredictionContainer;
import grex.fitnessfunctions.FitnessFunction;
import grex.fitnessfunctions.IFitnessFunction;
import grex.genes.Gene;
import grex.genes.GeneException;
import grex.genes.TargetPred;

import java.io.Serializable;

/**
 *
 * @author rik
 */
public class EntropyFitness extends FitnessFunction implements IFitnessFunction, Serializable {

    /** Creates a new instance of NormalFitness */
    public EntropyFitness() {
        super(FitnessFunction.ENTROPY);
    }
    @Override
    protected double calcFinalError(PredictionContainer pc){
        if(gp==null)
            return -1;
        return 100 * calcEntropy(gp.getHead(),pc.values().size());
    }
    private double calcEntropy(Gene gene,double n){
        Gene[] children = gene.getChildren();
        if(children == null){
            TargetPred tp = (TargetPred)gene; 
            if(tp.getCount()==0)
                return 1;
            return calcEntropy(tp.getProbs()) * tp.getCount() / n;
        }
        return calcEntropy(children[1],n) + calcEntropy(children[2], n);
    }

    @Override
    protected double calcPredictionError(Prediction prediction, double targetValue) {
        return 0;
    }

    protected double calcEntropy(double[] probs) {
        if(probs == null)
            return 0;
        
            double entropy = 0;
            for (int i = 0; i < probs.length; i++) { 
                if(probs[i]!=0)
                    entropy += -probs[i] * log2(probs[i]);
            }
            return entropy;        
    }
    
    private double log2(double value){
        return Math.log(value)/Math.log(2);
    }
}